#!/usr/bin/env python
# -*- coding: utf-8 -*-

import weakref
import functools
import itertools
import random


class RoundRobin(object):

    def __init__(self):
        self.instances = {}
        self.pool = []
        self.cycle = itertools.cycle(self.pool)

    def __relocate(self):
        self.pool = []
        for k, v in self.instances.items():
            for i in range(v):
                self.pool.append(k)
        if self.pool:
            random.shuffle(self.pool)
        self.cycle = itertools.cycle(self.pool)

    def __len__(self):
        return len(self.instances)

    def add(self, instance, weight=1):
        if not isinstance(instance, object):
            raise ValueError('RoundRobin instance must be object')
        if not isinstance(weight, int):
            raise ValueError('RoundRobin weight must be int')
        # ref = weakref.ref(instance, functools.partial(self.__delete))
        ref = instance
        self.instances[ref] = weight
        self.__relocate()

    def __delete(self, instance):
        self.instances.pop(instance, None)
        self.__relocate()

    def delete(self, instance):
        # ref = weakref.ref(instance)
        self.instances.pop(instance, None)
        self.__relocate()

    def __get(self):
        while self.cycle:
            yield self.cycle.next()

    def get(self):
        try:
            ref = self.__get().next()
        except StopIteration:
            return None
        # if ref:
        #     ref = ref()
        return ref

    def __str__(self):
        return '%r' % self.pool


if __name__ == '__main__':
    rr = RoundRobin()

    class A:

        def __init__(self, value):
            self.value = value

        def __str__(self):
            return str(self.value)

    a = A(323)
    b = A(321)
    c = A(322)
    rr.add(a, 1)
    rr.add(b, 2)
    rr.add(c, 3)
    print 'add...'
    for i in range(10):
        print rr.get()
    rr.delete(a)
    print 'delete...'
    for i in range(10):
        print rr.get()
    rr.delete(b)
    print 'delete... 2'
    for i in range(10):
        print rr.get()
    del c
    for i in range(10):
        print rr.get()
    print 'get success...'
    # print rr
